package org.goldenport.g3.servlet

import scala.collection.mutable.ArrayBuffer
import javax.servlet._
import javax.servlet.http._
import org.goldenport.g3._
import org.goldenport.g3.messages.Html
import org.goldenport.g3.messages.http._
import G3Servlet._

/*
 * @since   May.  8, 2010
 *  version Jun. 23, 2011
 * @version Dec.  5, 2011
 * @author  ASAMI, Tomoharu
 */
class G3Servlet(val activeApp: Option[G3Application]) extends HttpServlet {
  var app: G3Application = null
  var accessControlAllowOrigin: Option[String] = Some("*")
  var accessControlMaxAge: Int = 86400
  def newApplication: G3Application = null

  def this() = this(None)

  override def init(config: ServletConfig) {
    def usesubclass = {
      newApplication match {
      case null => None
      case a => Some(a)
      }
    }
    def newfromname = {
      val appName = config.getInitParameter("g3.application") match {
      case name: String => name
      case null => "App"
      }
      Some(Class.forName(appName).newInstance().asInstanceOf[G3Application])
    }
    app = (activeApp orElse usesubclass orElse newfromname).get
    if (activeApp.isEmpty) {
      open_Application(app, config)
    }
  }

  protected def open_Application(a: G3Application, config: ServletConfig) {
    a.openServlet(config)
  }

  override def destroy() {
    if (activeApp.isEmpty) {
      app.close()
    }
  }

  override def service(req: HttpServletRequest, resp: HttpServletResponse) {
    req.getMethod.toUpperCase match {
      case "MKCOL" => doMkcol(req, resp)
      case "COPY" => doCopy(req, resp)
      case "MOVE" => doMove(req, resp)
      case _ => super.service(req, resp)
    }
  }

  private def write_response(response: G3HttpResponse, resp: HttpServletResponse) {
    response.setResponse(resp)
//    response match {
//      case s: StringHttpResponse => {
//        write_response(
//            s.content, response.contentType, response.statusCode,
//            resp)
//      } 
//      case b: ByteArrayHttpResponse => {
//        write_response(
//            b.content, response.contentType, response.statusCode,
//            resp)
//      } 
//    }
  }

  private def write_response(page: String, ctype: String,
                             code: Int, 
                             resp: HttpServletResponse) {
    resp.setHeader("Access-Control-Allow-Origin", "*")
    resp.setContentType(ctype)
    resp.setStatus(code)
    val writer = resp.getWriter()
    try {
      writer.println(page)
      writer.flush()
    } finally {
      writer.close()
    }
  }

  private def write_response(page: Array[Byte], ctype: String,
                             code: Int, 
                             resp: HttpServletResponse) {
    resp.setHeader("Access-Control-Allow-Origin", "*")
    resp.setContentType(ctype)
    resp.setStatus(code)
    val out = resp.getOutputStream()
    try {
      out.write(page)
      out.flush()
    } finally {
      out.close()
    }
  }
  
  protected final def get_session(req: HttpServletRequest): Option[G3Session] = {
    import com.asamioffice.goldenport.util.OptionUtil.collect

    collect(req.getAttribute(SessionSession)) {
      case session: G3Session => session
    } orElse collect(req.getAttribute(SessionUser)) {
      case user: G3User => {
        val session = G3Session(user)
        req.setAttribute(SessionSession, session)
        session
      }
    }
  }

  override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {
    val get = GET(req)
    val response = app.executeHttp(get, get_session(req))
    write_response(response, resp)
    app.commit()
  }

  override def doPost(req: HttpServletRequest, resp: HttpServletResponse) {
    val post = POST(req)
    val response = app.executeHttp(post, get_session(req))
    write_response(response, resp)
    app.commit()
  }

  override def doPut(req: HttpServletRequest, resp: HttpServletResponse) {
    val put = PUT(req)
    val response = app.executeHttp(put, get_session(req))
    write_response(response, resp)
    app.commit()
  }

  override def doDelete(req: HttpServletRequest, resp: HttpServletResponse) {
    val delete = DELETE(req)
    val response = app.executeHttp(delete, get_session(req))
    write_response(response, resp)
    app.commit()
  }

  override def doOptions(req: HttpServletRequest, resp: HttpServletResponse) {
    for (origin <- accessControlAllowOrigin) {
      resp.setHeader("Access-Control-Allow-Origin", origin)
      resp.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS")
      resp.setHeader("Access-Control-Allow-Headers", req.getHeader("Access-Control-Request-Headers"))
      resp.setHeader("Access-Control-Max-Age", accessControlMaxAge.toString)
    }
    super.doOptions(req, resp)
  }

  def doMkcol(req: HttpServletRequest, resp: HttpServletResponse) {
    error("not implemented yet")
  }

  def doCopy(req: HttpServletRequest, resp: HttpServletResponse) {
    error("not implemented yet")
  }

  def doMove(req: HttpServletRequest, resp: HttpServletResponse) {
    error("not implemented yet")
  }
}

object G3Servlet {
  val LoginUri = "auth/login"
  val LogoutUri = "auth/logout"
  val AdminUri = "auth/admin"
  val SessionSession = "_session"
  val SessionUser = "_user"
  val SessionTarget = "_target"
  val Username = "_username"
  val LoginMessage = "_loginMessage"
  val LoginErrorMessage = "Login Error"

  def loginUri(req: HttpServletRequest): String = {
    import com.asamioffice.goldenport.servlet.ServletUtil.getContextPath

    getContextPath(req) + LoginUri
  }

  def logoutUri(req: HttpServletRequest): String = {
    import com.asamioffice.goldenport.servlet.ServletUtil.getContextPath

    getContextPath(req) + LogoutUri
  }
}
